package com.manxi.mall.util;

import org.apache.commons.lang3.time.DateFormatUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;

/**
 * 日期格式化工具类
 * 使用Java 8的时间API，线程安全，避免SimpleDateFormat的线程安全问题
 * 
 * @author Addroc
 * @date 2024/6/14
 */
public class DateFormatUtil {
    
    // 常用日期时间格式化器
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter PARTITION_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
    private static final DateTimeFormatter DATETIME_MINUTE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    private static final DateTimeFormatter COMPACT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    
    /**
     * 获取当前日期的yyyyMMdd格式整数表示
     * 
     * @return 当前日期的整数表示，如：20241214
     */
    public static Integer now() {
        String yyyyMMdd = DateFormatUtils.format(new Date(), "yyyyMMdd");
        return Integer.valueOf(yyyyMMdd);
    }
    
    /**
     * 获取当前日期字符串（yyyy-MM-dd格式）
     * 
     * @return 当前日期字符串，如：2024-12-14
     */
    public static String getCurrentDate() {
        return LocalDate.now().format(DATE_FORMATTER);
    }
    
    /**
     * 获取当前日期时间字符串（yyyy-MM-dd HH:mm:ss格式）
     * 
     * @return 当前日期时间字符串，如：2024-12-14 15:30:45
     */
    public static String getCurrentDateTime() {
        return LocalDateTime.now().format(DATETIME_FORMATTER);
    }
    
    /**
     * 获取当前时间戳（毫秒）
     * 
     * @return 当前时间戳
     */
    public static Long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }
    
    /**
     * 将日期时间字符串转换为时间戳（毫秒）
     * 
     * @param dateTime 日期时间字符串，格式：yyyy-MM-dd HH:mm:ss
     * @return 时间戳（毫秒）
     */
    public static Long dateTimeToTimestamp(String dateTime) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateTime, DATETIME_FORMATTER);
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }
    
    /**
     * 将日期字符串转换为时间戳（毫秒）
     * 默认时间为当天00:00:00
     * 
     * @param date 日期字符串，格式：yyyy-MM-dd
     * @return 时间戳（毫秒）
     */
    public static Long dateToTimestamp(String date) {
        return dateTimeToTimestamp(date + " 00:00:00");
    }
    
    /**
     * 将时间戳转换为日期字符串
     * 
     * @param timestamp 时间戳（毫秒）
     * @return 日期字符串，格式：yyyy-MM-dd
     */
    public static String timestampToDate(Long timestamp) {
        Date date = new Date(timestamp);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return DATE_FORMATTER.format(localDateTime);
    }
    
    /**
     * 将时间戳转换为日期时间字符串
     * 
     * @param timestamp 时间戳（毫秒）
     * @return 日期时间字符串，格式：yyyy-MM-dd HH:mm:ss
     */
    public static String timestampToDateTime(Long timestamp) {
        Date date = new Date(timestamp);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return DATETIME_FORMATTER.format(localDateTime);
    }
    
    /**
     * 将时间戳转换为分区格式日期字符串（用于数据分区）
     * 
     * @param timestamp 时间戳（毫秒）
     * @return 分区格式日期字符串，格式：yyyyMMdd
     */
    public static String timestampToPartitionDate(Long timestamp) {
        Date date = new Date(timestamp);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        return PARTITION_FORMATTER.format(localDateTime);
    }
    
    /**
     * 格式化Date对象为指定格式字符串
     * 
     * @param date 日期对象
     * @param pattern 格式模式
     * @return 格式化后的日期字符串
     */
    public static String format(Date date, String pattern) {
        return DateFormatUtils.format(date, pattern);
    }
    
    /**
     * 格式化LocalDateTime对象为指定格式字符串
     * 
     * @param localDateTime 本地日期时间对象
     * @param pattern 格式模式
     * @return 格式化后的日期字符串
     */
    public static String format(LocalDateTime localDateTime, String pattern) {
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }
    
    /**
     * 获取指定日期的开始时间（00:00:00）
     * 
     * @param date 指定日期，格式：yyyy-MM-dd
     * @return 开始时间字符串，格式：yyyy-MM-dd 00:00:00
     */
    public static String getStartOfDay(String date) {
        return date + " 00:00:00";
    }
    
    /**
     * 获取指定日期的结束时间（23:59:59）
     * 
     * @param date 指定日期，格式：yyyy-MM-dd
     * @return 结束时间字符串，格式：yyyy-MM-dd 23:59:59
     */
    public static String getEndOfDay(String date) {
        return date + " 23:59:59";
    }
    
    /**
     * 计算两个日期之间的天数差
     * 
     * @param startDate 开始日期，格式：yyyy-MM-dd
     * @param endDate 结束日期，格式：yyyy-MM-dd
     * @return 天数差
     */
    public static Long daysBetween(String startDate, String endDate) {
        LocalDate start = LocalDate.parse(startDate, DATE_FORMATTER);
        LocalDate end = LocalDate.parse(endDate, DATE_FORMATTER);
        return ChronoUnit.DAYS.between(start, end);
    }
    
    /**
     * 在指定日期基础上增加天数
     * 
     * @param date 基准日期，格式：yyyy-MM-dd
     * @param days 要增加的天数（可为负数）
     * @return 计算后的日期字符串，格式：yyyy-MM-dd
     */
    public static String addDays(String date, long days) {
        LocalDate localDate = LocalDate.parse(date, DATE_FORMATTER);
        return localDate.plusDays(days).format(DATE_FORMATTER);
    }
    
    /**
     * 在指定日期时间基础上增加小时
     * 
     * @param dateTime 基准日期时间，格式：yyyy-MM-dd HH:mm:ss
     * @param hours 要增加的小时数（可为负数）
     * @return 计算后的日期时间字符串，格式：yyyy-MM-dd HH:mm:ss
     */
    public static String addHours(String dateTime, long hours) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateTime, DATETIME_FORMATTER);
        return localDateTime.plusHours(hours).format(DATETIME_FORMATTER);
    }
    
    /**
     * 在指定日期时间基础上增加分钟
     * 
     * @param dateTime 基准日期时间，格式：yyyy-MM-dd HH:mm:ss
     * @param minutes 要增加的分钟数（可为负数）
     * @return 计算后的日期时间字符串，格式：yyyy-MM-dd HH:mm:ss
     */
    public static String addMinutes(String dateTime, long minutes) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateTime, DATETIME_FORMATTER);
        return localDateTime.plusMinutes(minutes).format(DATETIME_FORMATTER);
    }
    
    /**
     * 判断字符串是否为有效的日期格式（yyyy-MM-dd）
     * 
     * @param dateStr 日期字符串
     * @return true表示有效，false表示无效
     */
    public static boolean isValidDate(String dateStr) {
        try {
            LocalDate.parse(dateStr, DATE_FORMATTER);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 判断字符串是否为有效的日期时间格式（yyyy-MM-dd HH:mm:ss）
     * 
     * @param dateTimeStr 日期时间字符串
     * @return true表示有效，false表示无效
     */
    public static boolean isValidDateTime(String dateTimeStr) {
        try {
            LocalDateTime.parse(dateTimeStr, DATETIME_FORMATTER);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取紧凑格式的当前日期时间（yyyyMMddHHmmss）
     * 常用于生成唯一标识符
     * 
     * @return 紧凑格式日期时间字符串，如：20241214153045
     */
    public static String getCompactDateTime() {
        return LocalDateTime.now().format(COMPACT_DATETIME_FORMATTER);
    }
    
    /**
     * 获取当前周的开始日期（周一）
     * 
     * @return 周开始日期字符串，格式：yyyy-MM-dd
     */
    public static String getStartOfWeek() {
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.minusDays(now.getDayOfWeek().getValue() - 1);
        return startOfWeek.format(DATE_FORMATTER);
    }
    
    /**
     * 获取当前月的开始日期
     * 
     * @return 月开始日期字符串，格式：yyyy-MM-dd
     */
    public static String getStartOfMonth() {
        LocalDate now = LocalDate.now();
        return now.withDayOfMonth(1).format(DATE_FORMATTER);
    }
    
    /**
     * 获取当前年的开始日期
     * 
     * @return 年开始日期字符串，格式：yyyy-MM-dd
     */
    public static String getStartOfYear() {
        LocalDate now = LocalDate.now();
        return now.withDayOfYear(1).format(DATE_FORMATTER);
    }
}